package com.minelx.woods.task.core;

import com.minelx.landisk.filesystem.core.File;
import com.minelx.landisk.filesystem.core.init.OpenPolicy;
import com.minelx.statementsplus.CombinedSql;
import com.minelx.statementsplus.MajorSql;
import com.minelx.statementsplus.cha.base.TaskCommitment;
import com.minelx.woods.task.common.Node;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.IntStream;

import static com.minelx.landisk.filesystem.core.init.OpenPolicy.createANewOne;
import static java.util.stream.Collectors.toList;

public class SqlTaskValues implements ICombinedSqlTask {

	private static final String DEFAULT_MULTIPLE_VALUES = "";

	private static final String DEFAULT_ADDITIONAL_VALUES = "";

	private final CombinedSql combinedSql;

	private final File destination;

	private final Map<String, Predicate<String>> filterers;

	public SqlTaskValues(CombinedSql combinedSql, File destination, Map<String, Predicate<String>> filterers) {
		this.destination = destination;
		this.combinedSql = combinedSql;
		this.filterers = filterers;
	}

	@Override
	public Node<SqlTaskValues> split(Predicate<SqlTaskValues> neededSplitting) {
		return Node.create(this, SqlTaskValues::divide, neededSplitting);
	}

	List<SqlTaskValues> divide() {
		List<MajorSql> splittingMajors = combinedSql.major().split();
		List<File> tempFiles = prepareTempFiles(destination, splittingMajors.size());
		List<SqlTaskValues> result = new ArrayList<>();
		for (int at = 0; at < splittingMajors.size(); at++) {
			MajorSql majorSql = splittingMajors.get(at);
			File childDestination = tempFiles.get(at);
			CombinedSql newCombined = new CombinedSql(majorSql, combinedSql.children());
			result.add(new SqlTaskValues(newCombined, childDestination, filterers));
		}
		return result;
	}

	private List<File> prepareTempFiles(File owner, int size) {
		return IntStream.range(0, size)
				.mapToObj(index -> File.create(owner.path().sibling(owner.path().getName() + index + "_"), createANewOne()))
				.collect(toList());
	}

	public TaskCommitment toTaskCommitment() {
		return new TaskCommitment(
				combinedSql().major().head().loopId(),
				combinedSql().major().head().content(),
				String.join("\n", combinedSql().children()),
				DEFAULT_ADDITIONAL_VALUES,
				DEFAULT_MULTIPLE_VALUES);
	}

	public CombinedSql combinedSql() {
		return combinedSql;
	}

	public File destination() {
		return destination;
	}

	public Map<String, Predicate<String>> filterers() {
		return filterers;
	}
}
